﻿using System;
using System.Collections.Generic;
using System.ComponentModel;

namespace Phylogeny.Dendogram
{
    public abstract class DendoNodeBase : INotifyPropertyChanged
    {

        //the central config instance
        private TreeConfig _config;
        internal TreeConfig Config
        {
            get
            {
                return _config;
            }
        }

        //the distance value
        private double _distance;
        public double Distance
        {
            get
            {
                return _distance;
            }
            internal set
            {
                _distance = value;
                OnPropertyChanged("Distance");
                OnPropertyChanged("RoundedDistance");
                OnPropertyChanged("Height");
            }
        }

        public double RoundedDistance
        {
            get
            {
                return Math.Round(_distance, 1) ;
            }
        }

        //the actual height calculated from the distance and the scale factor of the central config
        public double Height
        {
            get
            {
                if (_distance > 0 || double.IsNaN(_distance))
                    return Math.Max(_distance * _config.ScaleFactor, 4);
                else
                    return 4;
            }
        }


        //indicates whether this node is a leaf
        public bool IsLeaf
        {
            get
            {
                return (SubNodeCount() == 1 && FirstChildNode().IsLeafLabel);
            }
        }

        //indicates whether this node is a leaf label
        public bool IsLeafLabel { get; internal set; }

        //indicates whether this node is the root
        public bool IsRoot { get; protected set; }

        //indicates whether this node is a inner node
        public bool IsInternalNode
        {
            get
            {
                return !IsRoot && !IsLeaf && !IsLeafLabel;
            }
        }


        //indicates whether this node is not the root and not leaf label
        public bool IsNode
        {
            get
            {
                return !IsRoot && !IsLeafLabel;
            }
        }

        //indicates whether this node the most left edge
        public bool IsLeftEdge
        {
            get
            {
                if (OwnerNodeCount() == 0)
                    return false;
                else
                    return FirstNode() == this;// _isLeft;
            }

        }

        //indicates whether this node the most right edge
        public bool IsRightEdge
        {
            get
            {
                if (OwnerNodeCount() == 0)
                    return false;
                else
                    return LastNode() == this;// _isLeft;
            }
        }

        public bool NodeLabelVisible
        {
            get
            {
                return (IsInternalNode && _config.ShowNodeLabel);
            }

        }

        public bool RootLabelVisible
        {
            get
            {
                return (IsRoot);
            }

        }

        public bool DistanceLabelVisible
        {
            get
            {
                return ((IsInternalNode || IsLeaf) && _config.ShowDistanceLabel);
            }

        }


        private string _title;
        public string Title
        {
            get
            {
                return _title;
            }
            set
            {
                _title = value;
                OnPropertyChanged("Title");
            }
        }

        private bool _selected;
        public bool IsSelected
        {
            get
            {
                return _selected;
            }
            set
            {
                _selected = value;
                OnPropertyChanged("IsSelected");
            }
        }



        public abstract int SubNodeCount();

        public abstract int OwnerNodeCount();

        public abstract DendoNodeBase FirstChildNode();

        public abstract DendoNodeBase FirstNode();

        public abstract DendoNodeBase LastNode();

        public abstract IEnumerable<DendoNodeBase> GetSubNodes();



        public DendoNodeBase(TreeConfig conf)
        {
            _config = conf;
            _config.PropertyChanged += new PropertyChangedEventHandler(_config_PropertyChanged);
        }



        void _config_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {

            OnPropertyChanged("Height");
            OnPropertyChanged("NodeLabelVisible");
            OnPropertyChanged("DistanceLabelVisible");
        }



        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string p)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(p));
        }
        #endregion
    }
}
